'''
Created on Nov 19, 2010

@author: dexen
'''

import time

from dexen.system.common.transact import SlaveTransact, SlaveRecvTransact


#===============================================================================
# Constants
#===============================================================================
M_CRASHED = "MASTER CRASHED"
M_RUNNING = "MASTER RUNNING"
M_STOPPED = "MASTER STOPPED (BY USER)"
M_FINISHED = "MASTER STOPPED (BY MASTER)"

#===============================================================================
# State Classes
#===============================================================================
class MasterState(object):
    def __init__(self, task_states, num_inds, slave_data, state):
        self.task_states = task_states
        self.num_inds = num_inds
        self._slave_data = slave_data
        self.state = state

    def is_finished(self):
        return self.state == M_FINISHED

    def get_task_states(self):
        return self.task_states
    
    def get_num_inds(self):
        self.num_inds
    
    def get_data(self, name):
        if not self._slave_data.has_key(name):
            return None
        return self._slave_data[name]
    
#===============================================================================
# Slave State
#===============================================================================
S_CRASHED = "SLAVE CRASHED"
S_BUSY = "SLAVE BUSY"
S_IDLE = "SLAVE IDLE"

class SlaveState(object):
    def __init__(self, name):
        self.name = name
        self.state = S_IDLE
    
    def update(self, transact):
        assert isinstance(transact, SlaveTransact)
        if isinstance(transact, SlaveRecvTransact):       
            if transact.has_slave_crashed():
                self.state = S_CRASHED
            else: self.state = S_IDLE
        
    def idle(self):
        self.state = S_IDLE
    
    def busy(self):
        self.state = S_BUSY
    
    def is_crashed(self):
        return self.state == S_CRASHED
    
    def is_busy(self):
        return self.state == S_BUSY
    
    def is_idle(self):
        return self.state == S_IDLE

#===============================================================================
# Job State
#===============================================================================
class JobState(object):
    def __init__(self, job_id, job_name, creation_time, state):
        self.job_id = job_id
        self.job_name = job_name
        self.creation_time = creation_time
        self.state = state
    
    def get_header(self):
        out = "|Job ID | Job Name |Creation Time|       Status       |\n"
        out += "-------------------------------------------------------"
        return out
    
    def _get_state_str(self):
        if self.state == M_CRASHED:
            return "CRASHED"
        if self.state == M_STOPPED:
            return "STOPPED (BY USER)"
        if self.state == M_FINISHED:
            return "STOPPED (BY MASTER)"
        if self.state == M_RUNNING:
            return "RUNNING"
    
    def __repr__(self):
        #c_time = time.strftime("%H:%M:%S",time.localtime(self.creation_time))
        out = "|{0:^7}|{1:^10}".format(self.job_id, self.job_name)
        c_time = self.creation_time
        out += "|{0:^13}".format(time.strftime("%H:%M:%S",time.localtime(c_time)))
        out += "|{0:^20}|".format(self._get_state_str())
        return out    
        
#===============================================================================
# TaskState
#===============================================================================
class TaskState(object):
    def __init__(self, name, label):
        self.name = name
        self.label = label
        self.n_pending_inds = 0
        self.n_processing_inds = 0
        self.n_successes = 0
        self.n_fails = 0
        self.tot_exec_time = 0.0
    
    def update(self, transact):
        assert isinstance(transact, SlaveRecvTransact)
        self.tot_exec_time += transact.get_exec_time()
        if transact.has_task_succeeded():
            self.n_successes += 1
        elif transact.has_task_failed():
            self.n_fails += 1
    
    @property
    def avg_exec_time(self):
        if self.n_successes == 0.0:
            return 0.0
        return self.tot_exec_time / self.n_successes
    
    @classmethod
    def get_header(cls):
        return "  ,ForTask,Pend,Proc,Succ,AvgTime"

    def get_log(self):
        out = "{0},".format(self.label)
        out += "{0},".format(self.n_pending_inds)
        out += "{0},".format(self.n_processing_inds)
        out += "{0},".format(self.n_successes)
        out += "{0:.2} secs".format(self.avg_exec_time)
        return out

    def __repr__(self):
        out = "-------------- TaskState ------------\n"
        out += "Name: {0}\n".format(self.name)
        out += "Label: {0}\n".format(self.label)
        out += "# Pending Inds: {0}\n".format(self.n_pending_inds)
        out += "# Processing Inds: {0}\n".format(self.n_processing_inds)
        out += "# Successful Execs: {0}\n".format(self.n_successes)
        out += "# Failed Execs: {0}\n".format(self.n_fails)
        out += "-------------------------------------\n"
        return out

